import * as React from 'react';
import {
    Dimensions,
    Image,
    Platform,
    StyleSheet,
    Text,
    Modal,
    View,
    TouchableOpacity,
    TouchableWithoutFeedback
} from 'react-native';
import { ButtonGroup } from 'react-native-elements';

import QRCode, { QRCodeProps } from 'react-native-qrcode-svg';

import QRSpeedMeterButton from './QRSpeedButton';
import Amount from './Amount';
import Button from './Button';
import CopyButton from './CopyButton';
import ShareButton from './ShareButton';
import NFCButton from './NFCButton';
import { localeString } from './../utils/LocaleUtils';
import { themeColor } from './../utils/ThemeUtils';
import Touchable from './Touchable';
import Conversion from './Conversion';
import { QRAnimationSpeed } from '../utils/QRAnimationUtils';

import Turtle from '../assets/images/SVG/Turtle.svg';
import Rabbit from '../assets/images/SVG/Rabbit.svg';
import Gazelle from '../assets/images/SVG/Gazelle.svg';

const defaultLogo = require('../assets/images/icon-black.png');
const defaultLogoWhite = require('../assets/images/icon-white.png');

type QRCodeElement = React.ElementRef<typeof QRCode>;

interface ExtendedQRCodeProps
    extends QRCodeProps,
        React.RefAttributes<QRCodeElement> {
    onLoad?: () => void;
    parent?: CollapsedQR;
}

interface ValueTextProps {
    value: string;
    truncateLongValue?: boolean;
    valueStyle?: any;
}

// Custom QR code component that forwards refs and handles component readiness
// Sets qrReady state on first valid component mount to prevent remounting cycles
const ForwardedQRCode = React.forwardRef<QRCodeElement, ExtendedQRCodeProps>(
    (props, ref) => (
        <QRCode
            {...props}
            getRef={(c) => {
                if (c && c.toDataURL && !(ref as any).current) {
                    (ref as any).current = c;
                    Image.getSize(
                        Image.resolveAssetSource(defaultLogo).uri,
                        () => {
                            props.parent?.setState({ qrReady: true });
                        }
                    );
                }
            }}
        />
    )
) as React.FC<ExtendedQRCodeProps>;

function ValueText({ value, truncateLongValue, valueStyle }: ValueTextProps) {
    const [state, setState] = React.useState<{
        numberOfValueLines: number | undefined;
    }>({ numberOfValueLines: truncateLongValue ? 3 : undefined });
    return truncateLongValue ? (
        <Touchable
            touch={() =>
                setState({
                    numberOfValueLines: state.numberOfValueLines ? undefined : 3
                })
            }
            highlight={false}
        >
            <Text
                style={{
                    ...styles.value,
                    ...valueStyle,
                    color: themeColor('secondaryText'),
                    minHeight: state.numberOfValueLines ? 50 : undefined
                }}
                numberOfLines={state.numberOfValueLines}
            >
                {value}
            </Text>
        </Touchable>
    ) : (
        <Text
            style={{
                ...styles.value,
                ...valueStyle,
                color: themeColor('secondaryText')
            }}
        >
            {value}
        </Text>
    );
}

interface CollapsedQRProps {
    value: string;
    valueStyle?: any;
    showText?: string;
    collapseText?: string;
    copyText?: string;
    copyValue?: string;
    iconContainerStyle?: any;
    showShare?: boolean;
    showSpeed?: boolean;
    iconOnly?: boolean;
    hideText?: boolean;
    expanded?: boolean;
    textBottom?: boolean;
    truncateLongValue?: boolean;
    logo?: any;
    nfcSupported?: boolean;
    satAmount?: string | number;
    displayAmount?: boolean;
    qrAnimationSpeed?: QRAnimationSpeed;
    onQRAnimationSpeedChange?: (speed: QRAnimationSpeed) => void;
}

interface CollapsedQRState {
    collapsed: boolean;
    enlargeQR: boolean;
    tempQRRef: React.RefObject<QRCodeElement> | null;
    qrReady: boolean;
    showSpeedOptions: boolean;
}

export default class CollapsedQR extends React.Component<
    CollapsedQRProps,
    CollapsedQRState
> {
    qrRef = React.createRef<QRCodeElement>();

    state = {
        collapsed: this.props.expanded ? false : true,
        enlargeQR: false,
        tempQRRef: null,
        qrReady: false,
        qrAnimationSpeed: this.props.qrAnimationSpeed,
        showSpeedOptions: false
    };

    toggleCollapse = () => {
        this.setState({
            collapsed: !this.state.collapsed
        });
    };

    handleQRCodeTap = () => {
        this.setState({ enlargeQR: !this.state.enlargeQR });
    };

    render() {
        const { collapsed, enlargeQR, tempQRRef, showSpeedOptions } =
            this.state;
        const {
            value,
            valueStyle,
            showText,
            copyText,
            copyValue,
            collapseText,
            iconContainerStyle,
            showShare,
            iconOnly,
            hideText,
            expanded,
            textBottom,
            truncateLongValue,
            logo,
            satAmount,
            qrAnimationSpeed,
            onQRAnimationSpeedChange,
            showSpeed
        } = this.props;

        const { width, height } = Dimensions.get('window');

        const QR_ANIMATION_SPEED_OPTIONS = [
            {
                value: 'slow',
                icon: Turtle
            },
            {
                value: 'medium',
                icon: Rabbit
            },
            {
                value: 'fast',
                icon: Gazelle
            }
        ];
        // Creates a temporary QR code for sharing and waits for component to be ready
        // Returns a promise that resolves when QR is fully rendered and ready to be captured
        const handleShare = () =>
            new Promise<void>((resolve) => {
                const tempRef = React.createRef<QRCodeElement>();
                this.setState({ tempQRRef: tempRef, qrReady: false }, () => {
                    const checkReady = () => {
                        if (this.state.qrReady) {
                            resolve();
                        } else {
                            requestAnimationFrame(checkReady);
                        }
                    };
                    checkReady();
                });
            });

        const supportsNFC =
            Platform.OS === 'android' && this.props.nfcSupported;

        const qrSpeedSelectedIndex = QR_ANIMATION_SPEED_OPTIONS.findIndex(
            (option) => option.value === qrAnimationSpeed
        );

        return (
            <React.Fragment>
                {/* Temporary QR for sharing */}
                {tempQRRef && (
                    <View style={{ height: 0, width: 0, overflow: 'hidden' }}>
                        <ForwardedQRCode
                            ref={tempQRRef}
                            value={value}
                            size={800}
                            logo={defaultLogo}
                            backgroundColor={'white'}
                            logoBackgroundColor={'white'}
                            logoMargin={10}
                            quietZone={40}
                            parent={this}
                        />
                    </View>
                )}

                {!hideText && !textBottom && (
                    <ValueText
                        value={value}
                        truncateLongValue={truncateLongValue}
                        valueStyle={valueStyle}
                    />
                )}
                {!collapsed && value && (
                    <View>
                        <TouchableOpacity
                            style={{
                                ...styles.qrPadding,
                                backgroundColor: themeColor('qr') || 'white'
                            }}
                            onPress={() => this.handleQRCodeTap()}
                        >
                            {enlargeQR && (
                                <Modal
                                    transparent={true}
                                    animationType="fade"
                                    visible={enlargeQR}
                                >
                                    <TouchableWithoutFeedback
                                        onPress={() => this.handleQRCodeTap()}
                                    >
                                        <View
                                            style={{
                                                flex: 1,
                                                justifyContent: 'center'
                                            }}
                                        >
                                            <View
                                                style={{
                                                    ...StyleSheet.absoluteFillObject,
                                                    backgroundColor: 'black',
                                                    opacity: 0.6
                                                }}
                                            />
                                            <View>
                                                <QRCode
                                                    value={value}
                                                    size={width}
                                                    logo={
                                                        logo
                                                            ? logo
                                                            : themeColor(
                                                                  'invertQrIcons'
                                                              )
                                                            ? defaultLogoWhite
                                                            : defaultLogo
                                                    }
                                                    backgroundColor={'white'}
                                                    logoBackgroundColor={
                                                        themeColor(
                                                            'invertQrIcons'
                                                        )
                                                            ? 'black'
                                                            : 'white'
                                                    }
                                                    logoMargin={10}
                                                    quietZone={width / 20}
                                                />
                                            </View>
                                        </View>
                                    </TouchableWithoutFeedback>
                                </Modal>
                            )}
                            <QRCode
                                value={value}
                                size={
                                    height > width ? width * 0.75 : height * 0.6
                                }
                                logo={
                                    logo
                                        ? logo
                                        : themeColor('invertQrIcons')
                                        ? defaultLogoWhite
                                        : defaultLogo
                                }
                                color={themeColor('qr') || 'black'}
                                backgroundColor={
                                    themeColor('qrBackground') || 'white'
                                }
                                logoBackgroundColor={
                                    themeColor('qrLogoBackground') || 'white'
                                }
                                logoMargin={10}
                                quietZone={width / 40}
                            />
                        </TouchableOpacity>
                        {satAmount != null && this.props.displayAmount && (
                            <View
                                style={{
                                    flexDirection: 'column',
                                    alignItems: 'center',
                                    alignSelf: 'center',
                                    backgroundColor:
                                        themeColor('buttonBackground') ||
                                        themeColor('secondary'),
                                    width:
                                        height > width
                                            ? width * 0.75
                                            : height * 0.6,
                                    borderBottomLeftRadius: 12,
                                    borderBottomRightRadius: 12,
                                    marginTop: -10,
                                    margin: 15,
                                    padding: 15
                                }}
                            >
                                <Amount
                                    sats={satAmount}
                                    toggleable
                                    jumboText
                                    colorOverride={themeColor('buttonText')}
                                ></Amount>
                                <View>
                                    <Conversion
                                        sats={satAmount}
                                        colorOverride={themeColor('buttonText')}
                                    />
                                </View>
                            </View>
                        )}
                    </View>
                )}
                {!hideText && textBottom && (
                    <ValueText
                        value={value}
                        truncateLongValue={truncateLongValue}
                        valueStyle={valueStyle}
                    />
                )}
                {!expanded && (
                    <Button
                        title={
                            collapsed
                                ? showText ||
                                  localeString('components.CollapsedQr.show')
                                : collapseText ||
                                  localeString('components.CollapsedQr.hide')
                        }
                        icon={{
                            name: 'qrcode',
                            type: 'font-awesome',
                            size: 25
                        }}
                        containerStyle={{
                            margin: 10
                        }}
                        onPress={() => this.toggleCollapse()}
                    />
                )}
                {showShare ? (
                    <View
                        style={{
                            flexDirection: 'row',
                            justifyContent: 'center'
                        }}
                    >
                        <CopyButton
                            iconContainerStyle={iconContainerStyle}
                            copyValue={copyValue || value}
                            title={copyText}
                            iconOnly={iconOnly}
                        />
                        <ShareButton
                            iconContainerStyle={
                                supportsNFC ? iconContainerStyle : undefined
                            }
                            value={copyValue || value}
                            qrRef={tempQRRef}
                            iconOnly={iconOnly}
                            onPress={handleShare}
                            onShareComplete={() =>
                                this.setState({ tempQRRef: null })
                            }
                        />
                        {supportsNFC && (
                            <NFCButton
                                value={copyValue || value}
                                iconOnly={iconOnly}
                            />
                        )}
                    </View>
                ) : (
                    <View
                        style={{
                            flexDirection: 'row',
                            justifyContent: 'center',
                            gap: 8
                        }}
                    >
                        {showSpeed && (
                            <QRSpeedMeterButton
                                showOptions={showSpeedOptions}
                                onPress={() =>
                                    this.setState({
                                        showSpeedOptions: !showSpeedOptions
                                    })
                                }
                                iconOnly={iconOnly}
                            />
                        )}
                        <CopyButton
                            copyValue={copyValue || value}
                            title={copyText}
                            iconOnly={iconOnly}
                        />

                        {supportsNFC && (
                            <NFCButton
                                value={copyValue || value}
                                iconOnly={iconOnly}
                            />
                        )}
                    </View>
                )}
                {showSpeedOptions && onQRAnimationSpeedChange && showSpeed && (
                    <View style={styles.speedOptions}>
                        <ButtonGroup
                            onPress={(index: number) => {
                                const selectedOption =
                                    QR_ANIMATION_SPEED_OPTIONS[index];
                                onQRAnimationSpeedChange(
                                    selectedOption.value as QRAnimationSpeed
                                );
                            }}
                            selectedIndex={qrSpeedSelectedIndex}
                            buttons={QR_ANIMATION_SPEED_OPTIONS.map(
                                (option, index) =>
                                    React.createElement(option.icon, {
                                        width: 36,
                                        height: 36,
                                        fill:
                                            qrSpeedSelectedIndex === index
                                                ? themeColor('secondary')
                                                : themeColor('secondaryText')
                                    })
                            )}
                            selectedButtonStyle={{
                                backgroundColor: themeColor('highlight'),
                                borderRadius: 12,
                                ...(Platform.OS === 'ios' && {
                                    alignItems: 'center',
                                    justifyContent: 'center'
                                })
                            }}
                            buttonStyle={{
                                ...(Platform.OS === 'ios' && {
                                    alignItems: 'center',
                                    justifyContent: 'center',
                                    paddingVertical: 8,
                                    paddingHorizontal: 4
                                })
                            }}
                            containerStyle={{
                                backgroundColor: themeColor('secondary'),
                                borderRadius: 12,
                                borderColor: themeColor('secondary'),
                                minWidth: 240,
                                alignSelf: 'center',
                                ...(Platform.OS === 'ios' && {
                                    height: 48
                                })
                            }}
                            innerBorderStyle={{
                                color: themeColor('secondary')
                            }}
                        />
                    </View>
                )}
            </React.Fragment>
        );
    }
}

const styles = StyleSheet.create({
    value: {
        marginBottom: 15,
        paddingLeft: 20,
        fontFamily: 'PPNeueMontreal-Book'
    },
    qrPadding: {
        alignItems: 'center',
        alignSelf: 'center',
        padding: 0,
        margin: 10
    },
    speedOptions: {
        marginTop: 10
    }
});
